/** ****************************************************************************
@addtogroup Beeper
@{
*******************************************************************************/

#include "beeper.h"

#define LOGTAG "BEEPER"

static void beeper_switch(driver_beeper_t* dev, switch_state_t state) {
	if(state == SWITCH_OFF) {
		beeper_stop(dev);
	} else {
		dev->funcPwmStart(dev->freq, dev->duty*100);
	}
}

void beeper_init(driver_beeper_t* dev, uint32_t freq, uint8_t duty) {
	if(!dev) { return; }
	dev->freq = freq;
	dev->duty = duty;
	dev->keepTime = 0;
	dev->startTime = 0;
	dev->note = NULL;
	dev->routineCheckTaskId = NULL;

	dev->blinkTaskId = NULL;
	dev->blinkExOnTime = 0;
	dev->state = SWITCH_OFF;
}

bool beeper_switchTo(driver_beeper_t* dev, switch_state_t state, uint32_t keepTime1, uint32_t keepTime2, uint8_t flashTimes) {
	if(!dev) { return false; }
	
    // 如果之前已经调过 blinkEx() ，则取消之前的
    beeper_stop(dev);

    if(state == SWITCH_OFF || state == SWITCH_ON) {
		beeper_switch(dev, state);
		bool changed = (!dev->state == !state); dev->state = state;
        return changed;
    }
	else if(state == SWITCH_TOGGLE) {
		dev->state = (switch_state_t)(!dev->state);
		beeper_switch(dev, state);
		return true;
    }
	else if(state == SWITCH_BLINK) {
        beeper_blinkEx(dev, keepTime1, keepTime2, flashTimes);
    }
    return false;
}

static void blinkHandler(uint8_t len, void* data) {
	if(!len || !data) { return; }
	driver_beeper_t* dev = (driver_beeper_t*)getPointer(data);
	if(!dev) { return; }
	beeper_switch(dev, SWITCH_OFF);
}

void beeper_blink(driver_beeper_t* dev, uint16_t time) {
	if(!dev || !time) { return; }
	beeper_switch(dev, SWITCH_ON);
	osTaskRunAfter(time, blinkHandler, sizeof(void*), &dev);
}

static void blinkExHandler(uint8_t len, void* data) {
	if(!len || !data) { return; }
	driver_beeper_t* dev = (driver_beeper_t*)getPointer(data);
	if(!dev) { return; }
	beeper_blink(dev, dev->blinkExOnTime);
}

uint16_t beeper_blinkEx(driver_beeper_t* dev, uint16_t onTime, uint16_t offTime, uint16_t count) {
	// 参数检查
	if(!(dev && onTime && offTime && count>1)) { return NULL; }
    dev->blinkExOnTime = onTime;

    // 如果之前已经调过 blinkEx() ，则取消之前的
    beeper_stop(dev);

    // 先闪第一次
    beeper_blink(dev, onTime);
    if(count != OSTASK_REPEAT_FOREVER) { count--; }

	// 安排后续的闪烁
	// 注意：需要把对象的指针传过去，以便在回调函数中访问对象
	return dev->blinkTaskId = osTaskRunEvery(onTime+offTime, count, blinkExHandler, sizeof(dev), &dev);
}

// 例行任务
static OSTaskDef(routineCheck) {
	if(cookieLen < sizeof(void*) || !cookieData) { return; }
	driver_beeper_t* dev = (driver_beeper_t*)getPointer(cookieData);

	if(osElapsedMs(dev->startTime) >= dev->keepTime) {
		// 当前音节未播放完，继续播放下一个音节
		beeper_play(dev, note_next(dev->note), dev->speed);
	}
}

void beeper_stop(driver_beeper_t* dev) {
	// 停止 PWM
	dev->funcPwmStop();
	// 停止例行任务
	osTaskDestroy(dev->routineCheckTaskId);
    // 如果之前已经调过 blinkEx() ，则取消之前的
    osTaskDestroy(dev->blinkTaskId);
	// 清空当前音乐
	dev->note = NULL;
}

bool beeper_play(driver_beeper_t* dev, const Note *note, uint16_t speed) {
	if(!dev || !note_validate(note) || !speed) {
		// 整个音乐播放完成
		logd("Beeper play end.\r\n");
		beeper_stop(dev);
		return false;
	}
	dev->note = note;
	dev->speed = speed;
	dev->startTime = osGetMs();
	dev->keepTime = BeatTime[note->beat] * 100L / speed;
	
	// 启动例行任务
	if(!dev->routineCheckTaskId) {
		logd("Beeper play begin ...\r\n");
		dev->routineCheckTaskId = osTaskRunRoutine(routineCheck, sizeof(void*), &dev);
	} else {
		//logd("Beeper play next  %d @ %d ...\r\n", note->tone, note->beat);
	}
	
	// 启动 PWM 输出
	dev->funcPwmStart(ToneFreq[note->tone], dev->duty*100);
	return true;
}
